﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NetworkingLibrary.Servers.Specialised
{
    public partial class ManagerServer : TCP.ITCPServer
    {
        private TCP.TCPServer TheTCPServer = null;

        public int MaxFlowRate
        {
            get
            {
                return TheTCPServer.MaxFlowRate;
            }
            set
            {
                TheTCPServer.MaxFlowRate = value;
            }
        }
        public DateTime LastSendTime
        {
            get
            {
                return TheTCPServer.LastSendTime;
            }
            set
            {
                TheTCPServer.LastSendTime = value;
            }
        }

        private Dictionary<System.Net.IPAddress, System.Net.IPAddress> gameServerAddresses = new Dictionary<System.Net.IPAddress, System.Net.IPAddress>();
        public Dictionary<System.Net.IPAddress, System.Net.IPAddress> GameServerAddresses 
        {
            get
            {
                return gameServerAddresses;
            }
        }

        public ManagerServer(int Port, string Addr, int? MaximumConnections = null)
        {
            TheTCPServer = new TCP.TCPServer();
            InitImplementation();

            if (!TheTCPServer.Start(Port, Addr, MaximumConnections))
            {
                throw new Exceptions.ServerStartException();
            }
            else
            {
                TheTCPServer.OnMessageReceived += new Events.MessageReceivedDelegate(TheTCPServer_OnMessageReceived);
            }
        }

        private void TheTCPServer_OnMessageReceived(Events.MessageReceivedEventArgs e)
        {
            try
            {
                Type MessageType = e.TheMessage.GetType();
                OnMessageReceived.Invoke(e);
                if (!e.PreventDefault)
                {
                    if (MessageType == typeof(Messages.Specialised.Manager.Requests.AddGameServerRequestMessage))
                    {
                        Messages.Specialised.Manager.Requests.AddGameServerRequestMessage TheMessage = (Messages.Specialised.Manager.Requests.AddGameServerRequestMessage)(e.TheMessage);
                        bool Added = false;
                        if (TheMessage.GameServerAddressTCP != null)
                        {
                            if (!gameServerAddresses.ContainsKey(TheMessage.GameServerAddressTCP))
                            {
                                gameServerAddresses.Add(TheMessage.GameServerAddressTCP, TheMessage.GameServerAddressUDP);
                                Added = true;
                            }
                            else
                            {
                                Added = true;
                            }
                        }

                        e.TheClient.Send(new Messages.Specialised.Manager.Responses.AddGameServerResponseMessage(Added));
                    }
                    else if (MessageType == typeof(Messages.Specialised.Manager.Requests.RemoveGameServerRequestMessage))
                    {
                        Messages.Specialised.Manager.Requests.RemoveGameServerRequestMessage TheMessage = (Messages.Specialised.Manager.Requests.RemoveGameServerRequestMessage)(e.TheMessage);
                        bool Removed = false;
                        if (TheMessage.GameServerAddress != null)
                        {
                            if (gameServerAddresses.ContainsKey(TheMessage.GameServerAddress))
                            {
                                Removed = gameServerAddresses.Remove(TheMessage.GameServerAddress);
                            }
                            else
                            {
                                Removed = true;
                            }
                        }
                        e.TheClient.Send(new Messages.Specialised.Manager.Responses.RemoveGameServerResponseMessage(Removed));
                    }
                    else if (MessageType == typeof(Messages.Specialised.Manager.Requests.RequestGameServersMessage))
                    {
                        Messages.Specialised.Manager.Requests.RequestGameServersMessage TheMessage = (Messages.Specialised.Manager.Requests.RequestGameServersMessage)(e.TheMessage);
                        Dictionary<System.Net.IPAddress, System.Net.IPAddress> HostAddresses = gameServerAddresses;
                        if (TheMessage.Offset != -1 && TheMessage.Count != -1)
                        {
                            int MaxOffset = HostAddresses.Count - 1;
                            int MaxCount = HostAddresses.Count - TheMessage.Offset;

                            if (TheMessage.Offset <= MaxOffset && TheMessage.Count <= MaxCount)
                            {
                                HostAddresses = HostAddresses.OrderBy(x => x.Key).ToDictionary(x => x.Key, y => y.Value);
                                HostAddresses = HostAddresses.ToList().GetRange(TheMessage.Offset, TheMessage.Count).ToDictionary(x => x.Key, y => y.Value);
                            }
                            else
                            {
                                HostAddresses = new Dictionary<System.Net.IPAddress, System.Net.IPAddress>();
                            }
                        }
                        e.TheClient.Send(new Messages.Specialised.Manager.Responses.GameServersResponseMessage(HostAddresses));
                    }
                }
            }
            catch (Exception ex)
            {
                OnError.Invoke(new Events.ErrorEventArgs(ex));
            }
        }

        #region ITCPServer Implementation

        public event Events.ClientConnectDelegate OnClientConnect = delegate { };
        public event Events.ClientDisconnectDelegate OnClientDisconnect = delegate { };
        public event Events.MaxConnectionsDelegate OnMaxConnections = delegate { };
        public event Events.MessageReceivedDelegate OnMessageReceived = delegate { };
        public event Events.ErrorDelegate OnError = delegate { };

        public int BufferSize
        {
            get
            {
                return TheTCPServer.BufferSize;
            }
            set
            {
                TheTCPServer.BufferSize = value;
            }
        }
        public bool Initialised
        {
            get
            {
                return TheTCPServer.Initialised;
            }
        }
        public bool Terminating
        {
            get
            {
                return TheTCPServer.Terminating;
            }
            set
            {
                TheTCPServer.Terminating = value;
            }
        }

        public int MaxConnections
        {
            get
            {
                return TheTCPServer.MaxConnections;
            }
            set
            {
                TheTCPServer.MaxConnections = value;
            }
        }

        public System.Net.IPAddress LocalAddress
        {
            get
            {
                return TheTCPServer.LocalAddress;
            }
        }

        public Dictionary<Guid, Clients.IClient> AllClients
        {
            get
            {
                return TheTCPServer.AllClients;
            }
        }

        public bool Initialise(int Port, string Addr)
        {
            return TheTCPServer.Initialise(Port, Addr);
        }
        public bool Start(int Port, string Addr, int? MaxConnections = null)
        {
            return TheTCPServer.Start(Port, Addr, MaxConnections);
        }
        public bool Stop()
        {
            return TheTCPServer.Stop();
        }

        public bool Send(byte[] TheBuffer)
        {
            return TheTCPServer.Send(TheBuffer);
        }
        public bool SendTo(byte[] TheBuffer, Guid ToID)
        {
            return TheTCPServer.SendTo(TheBuffer, ToID);
        }
        public bool Send(byte[] TheBuffer, Guid ExcludeID)
        {
            return TheTCPServer.Send(TheBuffer, ExcludeID);
        }
        public bool Send(Messages.MessageObject TheMessage)
        {
            return TheTCPServer.Send(TheMessage);
        }
        public bool SendTo(Messages.MessageObject TheMessage, Guid ToId)
        {
            return TheTCPServer.SendTo(TheMessage, ToId);
        }
        public bool Send(Messages.MessageObject TheMessage, Guid ExcludeID)
        {
            return TheTCPServer.Send(TheMessage, ExcludeID);
        }


        private void InitImplementation()
        {
            TheTCPServer.OnClientConnect += new Events.ClientConnectDelegate(TheTCPServer_OnClientConnect);
            TheTCPServer.OnClientDisconnect += new Events.ClientDisconnectDelegate(TheTCPServer_OnClientDisconnect);
            TheTCPServer.OnError += new Events.ErrorDelegate(TheTCPServer_OnError);
            TheTCPServer.OnMaxConnections += new Events.MaxConnectionsDelegate(TheTCPServer_OnMaxConnections);
        }

        private void TheTCPServer_OnClientConnect(Events.ClientConnectEventArgs e)
        {
            OnClientConnect.Invoke(e);
        }
        private void TheTCPServer_OnClientDisconnect(Events.ClientDisconnectEventArgs e)
        {
            OnClientDisconnect.Invoke(e);
        }
        private void TheTCPServer_OnError(Events.ErrorEventArgs e)
        {
            OnError.Invoke(e);
        }
        private void TheTCPServer_OnMaxConnections(Events.MaxConnectionsEventArgs e)
        {
            try
            {
                OnMaxConnections.Invoke(e);
            }
            catch (Exception ex)
            {
                OnError.Invoke(new Events.ErrorEventArgs(ex));
            }
        }

        #endregion
    }
}
